﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using Newtonsoft.Json;

namespace dogetrader.CryptsyAPI
{
    /**
     * API Communication with Cryptsy.  For any authenticated methods, the Properties.Settings.Default API keys must be set previously.  
     */
    class APIMethods
    {
        public delegate void SetProgressDelegate(int percent);

        /**
         * Make a secure query to the Cryptsy server using the user's public/secret API keys.  
         */
        private static string CryptsySecureQuery(string method, string extraPOSTData, SetProgressDelegate setProgress)
        {
            long nonce = (long)DateTime.Now.Subtract(new DateTime(2000, 1, 1)).TotalSeconds;

            HttpWebRequest httpWReq =
                (HttpWebRequest)WebRequest.Create("https://www.cryptsy.com/api");

            UTF8Encoding encoding = new UTF8Encoding();
            string postData = "method=" + method;
            postData += "&nonce=" + nonce;
            if (extraPOSTData.Trim() != "") postData += extraPOSTData;
            byte[] postDataBytes = encoding.GetBytes(postData);

            System.Security.Cryptography.HMACSHA512 hmac = new System.Security.Cryptography.HMACSHA512(
                encoding.GetBytes(Properties.Settings.Default.secretAPIKey));
            hmac.ComputeHash(postDataBytes);
            StringBuilder encryptedPostDataBuilder = new StringBuilder();
            foreach (byte hashByte in hmac.Hash)
            {
                encryptedPostDataBuilder.Append(hashByte.ToString("x2"));
            }

            httpWReq.Method = "POST";
            httpWReq.CookieContainer = new CookieContainer();
            httpWReq.ContentType = "application/x-www-form-urlencoded";
            httpWReq.ContentLength = postDataBytes.Length;
            httpWReq.Headers.Add("Sign", encryptedPostDataBuilder.ToString());
            httpWReq.Headers.Add("Key", Properties.Settings.Default.publicAPIKey);

            using (Stream stream = httpWReq.GetRequestStream())
            {
                stream.Write(postDataBytes, 0, postDataBytes.Length);
            }

            setProgress(50);

            //get the response from Cryptsy
            HttpWebResponse response = (HttpWebResponse)httpWReq.GetResponse();

            setProgress(75);

            string responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

            return responseString;
        }

        public static CreateOrder CryptsyCreateOrderDOGE(bool buy, double dogeQuantity, double dogePriceInBTC, SetProgressDelegate setProgress)
        {
            string extraPOSTData = "&marketid=132";
            extraPOSTData += "&ordertype=" + ((buy)? "Buy" : "Sell");
            extraPOSTData += string.Format("&quantity={0:0.000000000}", dogeQuantity);
            extraPOSTData += string.Format("&price={0:0.000000000}", dogePriceInBTC);
            string jsonString = CryptsySecureQuery("createorder", extraPOSTData, setProgress);
            CreateOrder createOrder = JsonConvert.DeserializeObject<CreateOrder>(jsonString);

            if (createOrder.success != 1)
            {
                string error = "";
                if (createOrder.error != null) error = createOrder.error;
                throw new Exception("Could not place order: " + error);
            }

            setProgress(100);
            return createOrder;
        }

        /**
         * Get the current coin balances from Cryptsy.  Currently only BTC and DOGE are implemented.  
         */
        public static void CryptsyGetInfo(out double btcAvailable, out double dogeAvailable, SetProgressDelegate setProgress)
        {
            string jsonString = CryptsySecureQuery("getinfo", "", setProgress);
            //parse the JSON string
            GetInfo dogeInfo = JsonConvert.DeserializeObject<GetInfo>(jsonString);

            if (dogeInfo.success != 1)
            {
                string error = "";
                if (dogeInfo.error != null) error = dogeInfo.error;
                throw new Exception("Could not retrieve Cryptsy balances: " + error);
            }

            btcAvailable = dogeInfo.@return.balances_available.BTC;
            dogeAvailable = dogeInfo.@return.balances_available.DOGE;

            setProgress(100);
        }
    }
}
